package ntriples

import "fmt"
import "code.google.com/p/project/trigger/rdf"
import "io"
import "strings"

// TODO make integer abbrevioation conditional on some flag
// (because N-TRIPLEs doesn't have it, but we want it for
// Turtle).

func Nt_writer(out io.Writer, g rdf.Graph) {
    g.FindAll(rdf.EVERY, func(t rdf.Triple) bool { nt_write_triple(out, t); return false })
}

func nt_write_triple(out io.Writer, t rdf.Triple) {
    nt_write_term(out, t.S)
    fmt.Print(" ")
    nt_write_term(out, t.P)
    fmt.Print(" ")
    nt_write_term(out, t.O)
    fmt.Println(" .")
}

func nt_write_term(out io.Writer, t rdf.Term) {
    switch t.Type() {
        case rdf.T_NONE:
            fmt.Fprint(out, "NONE" )

        case rdf.T_IRI:
            // TODO there are escapes for IRI strings
            fmt.Fprint(out, "<" )
            fmt.Fprint(out, t.Spelling() )
            fmt.Fprint(out, ">" )

        case rdf.T_BNODE:
            fmt.Fprint(out, t.Spelling() )

        case rdf.T_LITERAL:
            // TODO string escapes. 
            lang, ty := t.Language(), t.DatatypeIRI()
            if ty == rdf.XSD_integer {
                fmt.Fprint( out, t.Spelling() )
            } else {
                fmt.Fprint(out, "\"" )
				writeEscaped(out, t.Spelling())
                fmt.Fprint(out, "\"" )
                if lang != "" { fmt.Fprint(out,"@"); fmt.Fprint(out, lang ) }
                if ty != rdf.AsIRI("") { fmt.Fprint(out,"^^<"); fmt.Fprint(out,ty.Spelling()); fmt.Fprint(out,">") }
            }

        case rdf.T_VAR:
            fmt.Fprint(out, "?" )
            fmt.Fprint(out, t.Spelling() )

        case rdf.T_SYMBOL:
            fmt.Fprint(out, t.Spelling() )

        default:
            panic("unreachable")
    }
}

func writeEscaped(out io.Writer, s string) {
	for {
		where := strings.IndexAny(s, "\r\n\t\"\\")
		if where < 0 { break }
		out.Write([]byte(s[:where]))
		ch := s[where]
		switch ch{
		case '\n': out.Write([]byte{'\\', 'n'}) 
		case '\t': out.Write([]byte{'\\', 't'})
		case '\r': out.Write([]byte{'\\', 'r'}) 
		case '\\': out.Write([]byte{'\\', '\\'}) 
		case '"': out.Write([]byte{'\\', '"'})
		}
		s = s[where+1:]		
	}
	out.Write([]byte(s))
}
